package com.mlx.mbg.code.method;

import com.mlx.mbg.code.MbgUtil;
import com.mlx.mbg.code.inter.EnableMethod;
import com.mlx.mbg.code.config.MbgPropertyConfig;
import com.mlx.mbg.code.inter.ExtensionLevel;
import com.mlx.mbg.code.inter.IExtensionMethod;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;

import java.util.ArrayList;
import java.util.List;

@EnableMethod
public class SelectCollectionMethod implements IExtensionMethod {
    @Override
    public boolean checkConfig(ExtensionLevel level, MbgPropertyConfig mbgPropertyConfig, IntrospectedTable introspectedTable) {
        return getExtensionLevelSet().contains(level) && mbgPropertyConfig.getEnableSelectCollection() && MbgUtil.checkInterfaceExpressionFormat(introspectedTable, "集合查询", "selectCollection");
    }

    @Override
    public int getOrder() {
        return 1500;
    }

    @Override
    public List<Method> buildMethod(IntrospectedTable introspectedTable) {
        List<Method> methodList = new ArrayList<>();
        String tableName = introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime();
        String collectionSelectFormatString = introspectedTable.getTableConfigurationProperty("selectCollection");

        String[] collectionSelectColumnStrings = collectionSelectFormatString.split(";");

        for (String collectionSelectColumnString : collectionSelectColumnStrings){
            String[] collectionSelectColumns = collectionSelectColumnString.split(",");
            List<IntrospectedColumn> keyColumnList = new ArrayList<IntrospectedColumn>();
            for (String collectionSelectColumn : collectionSelectColumns){
                IntrospectedColumn column = introspectedTable.getColumn(collectionSelectColumn);
                keyColumnList.add(column);
            }

            IntrospectedColumn lastColumn = keyColumnList.remove(keyColumnList.size() - 1);
            FullyQualifiedJavaType lastJavaType = lastColumn.getFullyQualifiedJavaType();
            String lastJavaProperty = lastColumn.getJavaProperty();
            String lastJavaPropertyUp = lastJavaProperty.substring(0, 1).toUpperCase() + lastJavaProperty.substring(1);
            String lastJavaPropertyCollection = lastJavaProperty + "Collection";

            JavaVisibility methodVisibility = JavaVisibility.PUBLIC;

            // 设置返回类型：实体类类型
            FullyQualifiedJavaType methodReturnType = new FullyQualifiedJavaType("List");
            methodReturnType.addTypeArgument(new FullyQualifiedJavaType(introspectedTable.getBaseRecordType()));

            StringBuilder methodName = new StringBuilder("listBy");
            StringBuilder remarkItem = new StringBuilder();
            for (IntrospectedColumn column : keyColumnList){
                String javaProperty = column.getJavaProperty();
                remarkItem.append(javaProperty).append(",");

                String javaPropertyUp0 = javaProperty.substring(0, 1).toUpperCase() + javaProperty.substring(1);
                methodName.append(javaPropertyUp0);
            }
            remarkItem.append(lastJavaPropertyCollection);
            methodName.append(lastJavaPropertyUp).append("Collection");

            List<Parameter> methodParameterList = new ArrayList<Parameter>();
            for (IntrospectedColumn column : keyColumnList){

                String javaProperty = column.getJavaProperty();

                FullyQualifiedJavaType javaType = column.getFullyQualifiedJavaType();

                // 参数类型
                FullyQualifiedJavaType methodParameterType = new FullyQualifiedJavaType(javaType.getShortName());

                // 方法参数
                Parameter methodParameter = new Parameter(methodParameterType, javaProperty);

                methodParameterList.add(methodParameter);

            }
            FullyQualifiedJavaType lastParameterType = new FullyQualifiedJavaType("Collection");
            lastParameterType.addTypeArgument(lastJavaType);
            methodParameterList.add(new Parameter(lastParameterType, lastJavaPropertyCollection));

            Method method = new Method();
            method.setVisibility(methodVisibility);
            method.setReturnType(methodReturnType);
            method.setName(methodName.toString());
            for (Parameter parameter : methodParameterList){
                method.addParameter(parameter);
            }
            method.addJavaDocLine("/**");
            method.addJavaDocLine(" * 集合查询：通过" + remarkItem + "查询");
            method.addJavaDocLine(" */");

            methodList.add(method);
        }

        return methodList;
    }

    @Override
    public List<XmlElement> buildSQL(IntrospectedTable introspectedTable) {
        List<XmlElement> elementList = new ArrayList<>();
        String tableName = introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime();
        String collectionSelectFormatString = introspectedTable.getTableConfigurationProperty("selectCollection");

        String[] collectionSelectColumnStrings = collectionSelectFormatString.split(";");

        for (String collectionSelectColumnString : collectionSelectColumnStrings){
            String[] collectionSelectColumns = collectionSelectColumnString.split(",");
            List<IntrospectedColumn> keyColumnList = new ArrayList<IntrospectedColumn>();
            for (String collectionSelectColumn : collectionSelectColumns){
                IntrospectedColumn column = introspectedTable.getColumn(collectionSelectColumn);
                keyColumnList.add(column);
            }

            IntrospectedColumn lastColumn = keyColumnList.remove(keyColumnList.size() - 1);
            String lastActualColumnName = lastColumn.getActualColumnName();
            String lastJdbcTypeName = lastColumn.getJdbcTypeName();
            String lastJavaProperty = lastColumn.getJavaProperty();
            String lastJavaPropertyUp = lastJavaProperty.substring(0, 1).toUpperCase() + lastJavaProperty.substring(1);
            String lastJavaPropertyCollection = lastJavaProperty + "Collection";

            XmlElement where = new XmlElement("where");

            XmlElement choose = new XmlElement("choose");

            XmlElement when = new XmlElement("when");
            when.addAttribute(new Attribute("test", lastJavaPropertyCollection + " == null or "+ lastJavaPropertyCollection + ".size == 0"));
            when.addElement(new TextElement("and false"));

            XmlElement otherwise = new XmlElement("otherwise");


            StringBuilder methodName = new StringBuilder("listBy");
            StringBuilder remarkItem = new StringBuilder();
            for (IntrospectedColumn column : keyColumnList){
                String actualColumnName = column.getActualColumnName();
                String jdbcTypeName = column.getJdbcTypeName();
                String javaProperty = column.getJavaProperty();
                remarkItem.append(javaProperty).append(",");

                String substring0 = javaProperty.substring(0, 1);
                String substring1 = javaProperty.substring(1);
                String javaPropertyUp0 = substring0.toUpperCase() + substring1;
                methodName.append(javaPropertyUp0);

                otherwise.addElement(new TextElement("and " + actualColumnName + " = #{" + javaProperty + ",jdbcType=" + jdbcTypeName + "}"));
            }
            remarkItem.append(lastJavaPropertyCollection);
            methodName.append(lastJavaPropertyUp).append("Collection");

            otherwise.addElement(new TextElement("and " + lastActualColumnName + " in "));

            XmlElement foreach = new XmlElement("foreach");
            foreach.addAttribute(new Attribute("collection", lastJavaPropertyCollection));
            foreach.addAttribute(new Attribute("item", lastJavaProperty));
            foreach.addAttribute(new Attribute("open", "("));
            foreach.addAttribute(new Attribute("separator", ","));
            foreach.addAttribute(new Attribute("close", ")"));

            foreach.addElement(new TextElement("#{"+ lastJavaProperty +",jdbcType=" + lastJdbcTypeName + "}"));

            otherwise.addElement(foreach);

            choose.addElement(when);
            choose.addElement(otherwise);

            where.addElement(choose);

            XmlElement method = new XmlElement("select");
            TextElement text3 = new TextElement("select");
            method.addAttribute(new Attribute("id", methodName.toString()));
            method.addAttribute(new Attribute("resultMap", "BaseResultMap"));
            XmlElement baseInclude = new XmlElement("include");
            baseInclude.addAttribute(new Attribute("refid", "Base_Column_List"));
            TextElement text4 = new TextElement("from " + introspectedTable.getFullyQualifiedTableNameAtRuntime());
            method.addElement(text3);
            method.addElement(baseInclude);
            method.addElement(text4);
            method.addElement(where);

            elementList.add(method);
        }

        return elementList;
    }
}
